package com.atguigu.gmall.service.impl;

import com.atguigu.gmall.cart.entity.UserAuth;
import com.atguigu.gmall.common.config.interceptor.component.UserAuthComponent;
import com.atguigu.gmall.common.consts.RedisConst;
import com.atguigu.gmall.common.execption.GmallException;
import com.atguigu.gmall.common.result.Result;
import com.atguigu.gmall.common.result.ResultCodeEnum;
import com.atguigu.gmall.common.util.JsonUtil;
import com.atguigu.gmall.common.util.MathUtil;
import com.atguigu.gmall.component.CartRepository;
import com.atguigu.gmall.feign.product.SkuDetailItemFeignClient;
import com.atguigu.gmall.model.cart.entity.CartInfo;
import com.atguigu.gmall.model.cart.vo.AddSuccessVo;
import com.atguigu.gmall.model.product.entity.SkuInfo;
import com.atguigu.gmall.service.CartService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.time.Duration;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author:lyd
 **/
@Service
@Slf4j
public class CartServiceImpl implements CartService {
    @Autowired
    StringRedisTemplate redisTemplate;
    @Autowired
    UserAuthComponent userAuthComponent;
    @Autowired
    CartRepository cartRepository;
    @Autowired
    SkuDetailItemFeignClient skuDetailItemFeignClient;

    @Override
    public AddSuccessVo addCart(String cartKey, Long skuId, Long skuNum) {
        AddSuccessVo vo = new AddSuccessVo();
        if (cartRepository.hasKey(cartKey, skuId.toString())) {
            //购物车有商品，增加数量即可
            CartInfo cart = cartRepository.getCart(cartKey, skuId.toString());
            if (cart != null) {
                cart.setSkuNum(cart.getSkuNum() + skuNum);
            }
            cartRepository.saveCart(cartKey, skuId.toString(), cart);
            SkuInfo skuInfo = cartInfoToSkuInfo(cart);
            vo.setSkuInfo(skuInfo);
            vo.setSkuNum(cart.getSkuNum());
        } else {
            //限制购物车添加商品的数量，不能超过5
            Long size = cartRepository.getCartSize(cartKey);
            if (size + 1 > RedisConst.CART_TOTAL_LIMIT) {
                throw new GmallException(ResultCodeEnum.CART_TOTAL_LIMIT);
            }
            //购物车没有商品，创建购物车，并保存到redis中
            Result<SkuInfo> skuInfo = skuDetailItemFeignClient.getSkuInfo(skuId);
            SkuInfo data = skuInfo.getData();
            CartInfo cartInfo = skuInfoToCartInfo(data, skuNum);
            cartRepository.saveCart(cartKey, skuId.toString(), cartInfo);
            vo.setSkuInfo(data);
            vo.setSkuNum(skuNum);
        }
        //设置临时购物车过期时间
        Long userId = userAuthComponent.getUserAuth().getUserId();
        if (StringUtils.isEmpty(userId)) {
            Long expire = redisTemplate.getExpire(cartKey);
            if (expire != null && expire < 0) {
                //第一次给临时购物车设置过期时间
                cartRepository.setCartTtl(cartKey, Duration.ofDays(365));
            }
        }

        return vo;
    }

    /**
     * 将CartInfo转换为SkuInfo
     *
     * @param info
     * @return
     */
    private SkuInfo cartInfoToSkuInfo(CartInfo info) {
        SkuInfo skuInfo = new SkuInfo();
        skuInfo.setId(info.getSkuId());
        skuInfo.setPrice(info.getCartPrice());
        skuInfo.setSkuName(info.getSkuName());
        skuInfo.setSkuDefaultImg(info.getImgUrl());
        return skuInfo;
    }

    /**
     * 将SkuInfo转换为CartInfo
     *
     * @param data
     * @param skuNum
     * @return
     */
    private CartInfo skuInfoToCartInfo(SkuInfo data, Long skuNum) {
        CartInfo cartInfo = new CartInfo();
        cartInfo.setSkuId(data.getId());
        //商品第一次加入购物车的价格
        cartInfo.setCartPrice(data.getPrice());
        //商品的实时价格
        cartInfo.setSkuPrice(data.getPrice());
        cartInfo.setSkuNum(skuNum);
        cartInfo.setImgUrl(data.getSkuDefaultImg());
        cartInfo.setSkuName(data.getSkuName());
        cartInfo.setIsChecked(1);
        cartInfo.setCreateTime(new Date());
        cartInfo.setUpdateTime(new Date());
        return cartInfo;
    }

    @Override
    public String determineCartKey() {
        UserAuth userAuth = userAuthComponent.getUserAuth();
        return RedisConst.CART_KEY_PREFIX + (userAuth.getUserId() != null ? userAuth.getUserId() : userAuth.getUserTempId());
    }

    @Override
    public List<CartInfo> cartList(String cartKey) {
        UserAuth userAuth = userAuthComponent.getUserAuth();
        //合并购物车
        if (userAuth.getUserId() != null) {
            List<CartInfo> cartList = cartRepository.cartList(RedisConst.CART_KEY_PREFIX + userAuth.getUserTempId());
            if (cartList != null && !cartList.isEmpty()) {
                log.info("购物车合并中：把 {} 数据合并到 {}", RedisConst.CART_KEY_PREFIX + userAuth.getUserTempId(), RedisConst.CART_KEY_PREFIX + userAuth.getUserId());
                for (CartInfo cartInfo : cartList) {
                    //用户购物车有则数量加一，无则从新添加
                    try {
                        //处理合并购物车时商品总数溢出购物车的最大值
                        addCart(RedisConst.CART_KEY_PREFIX + userAuth.getUserId(), cartInfo.getSkuId(), cartInfo.getSkuNum());
                        //合并一个商品，删除临时购物中一个商品的数据
                        cartRepository.deleteItem(RedisConst.CART_KEY_PREFIX + userAuth.getUserTempId(), cartInfo.getSkuId().toString());
                    } catch (GmallException e) {
                        throw new GmallException(ResultCodeEnum.CART_TEMP_TOO_MUCH);
                    }
                }
            }

        }
        List<CartInfo> cartList = cartRepository.cartList(cartKey);
        //更新购物车商品的价格
        cartList.stream()
                .parallel()
                .forEach(cartInfo -> {
                    BigDecimal skuPrice = cartInfo.getSkuPrice();
                    BigDecimal realPrice = skuDetailItemFeignClient.getSkuPrice(cartInfo.getSkuId()).getData();
                    if (!MathUtil.decimalEquals(skuPrice, realPrice)) {
                        log.info("商品价格发生变化，商品id：{}，商品价格由：{}，变为：{}", cartInfo.getSkuId(), skuPrice, realPrice);
                        //价格不一样，修改
                        cartInfo.setSkuPrice(realPrice);
                        cartRepository.saveCart(cartKey, cartInfo.getSkuId().toString(), cartInfo);
                    }
                });

        return cartList;
    }

    @Override
    public void checkCart(String cartKey, Long skuId, Integer isChecked) {
        CartInfo cart = cartRepository.getCart(cartKey, skuId.toString());
        cart.setIsChecked(isChecked);
        cartRepository.saveCart(cartKey, skuId.toString(), cart);
    }

    @Override
    public void deleteCartBySkuId(String cartKey, Long skuId) {
        cartRepository.remove(cartKey, skuId.toString());
    }

    @Override
    public void incrOrDecr(String cartKey, Long skuId, Long num) {
        CartInfo cart = cartRepository.getCart(cartKey, skuId.toString());
        cart.setSkuNum(cart.getSkuNum() + num);
        if (cart.getSkuNum() <= 0) {
            throw new GmallException(ResultCodeEnum.SKU_INFO_CART_NOT_ZERO);
        }
        cartRepository.saveCart(cartKey, skuId.toString(), cart);
    }

    @Override
    public void deleteChecked(String cartKey) {
        cartRepository.deleteChecked(cartKey);
    }

    @Override
    public List<CartInfo> userList(String cartKey) {
        return cartRepository.cartList(cartKey);
    }

    @Override
    public List<CartInfo> checkedList(String cartKey) {
        HashOperations<String, String, String> hash = redisTemplate.opsForHash();
        List<CartInfo> cartInfos = hash.values(cartKey)
                .stream()
                .map(item -> JsonUtil.strToObj(item, CartInfo.class))
                .filter(cartInfo -> cartInfo.getIsChecked() == 1)
                .collect(Collectors.toList());
        return cartInfos;

    }
}
